package pool

import (
	"errors"
	"fmt"
	"sync"
	"time"
)

// 存放连接的
type channelPool struct {
	mu sync.Mutex
	conns	chan *idleConn
	factory func()(interface{}, error)
	close func(interface{}) error
	ping func(interface{}) error
	idleTimeout	time.Duration
}

type idleConn struct {
	conn interface{}
	t time.Time
}

func (this *channelPool) GetConnS() chan *idleConn {
	this.mu.Lock()
	defer this.mu.Unlock()
	return this.conns
}

func (this *channelPool) Get() (interface{}, error) {
	conns := this.GetConnS()
	if conns == nil {
		return nil, errors.New("当前无连接")
	}
	for {
		select {
			case wrapConn := <- conns:
				ok, err := this.checkConnAvailability(wrapConn)
				if err != nil {
					return nil, err
				}
				if !ok {
					continue
				}
				return wrapConn.conn, nil
		default:
			this.mu.Lock()
			defer this.mu.Unlock()
			conn, err := this.factory()
			if err != nil {
				return nil, fmt.Errorf("连接数已用完，创建连接失败")
			}
			return conn, nil
		}
	}
}

func (this *channelPool) checkConnAvailability(wrapConn *idleConn) (bool, error) {
	// 判断是否超时
	if timeout := this.idleTimeout; timeout > 0 {
		if wrapConn.t.Add(timeout).Before(time.Now()) {
			// 丢弃并关闭连接
			this.close(wrapConn.conn)
			return false, nil
		}
	}
	// 判断是否ping的通
	if this.ping != nil {
		if err := this.ping(wrapConn.conn); err != nil{
			return false, fmt.Errorf("连接不通")
		}
	}
	return true, nil
}

// 将连接放回池子中
func (this *channelPool) Put(conn interface{}) error {
	//panic("implement me")
	this.mu.Lock()
	defer this.mu.Unlock()
	select {
	case this.conns <- &idleConn{conn: conn, t: time.Now()}:
		return nil
	default:
		//连接池已满，直接关闭该连接
		return this.Close(conn)
	}
}

func (this *channelPool) Close(conn interface{}) error {
	return this.Close(conn)
}

func (this *channelPool) Len() int {
	this.mu.Lock()
	defer this.mu.Unlock()
	return len(this.conns)
}


func (this *channelPool) Release (){
	this.mu.Lock()
	conns := this.conns
	this.conns = nil
	this.factory = nil
	closeFunc := this.close
	this.close = nil
	this.mu.Unlock()

	if conns == nil {
		return
	}

	close(conns)
	for wrapConn :=range conns {
		closeFunc(wrapConn.conn)
	}
}

// 初始化连接
func NewChannelPool(cfg *Config) (Pool, error) {
	if cfg.InitialCap < 0 || cfg.MaxCap <= 0 || cfg.InitialCap > cfg.MaxCap {
		return nil, errors.New("初始化连接数配置异常")
	}
	if cfg.Factory == nil {
		return nil, errors.New("非法 factory 方法")
	}
	if cfg.Close == nil {
		return nil, errors.New("非法 close 方法")
	}

	c := &channelPool{
		conns: make(chan *idleConn, cfg.MaxCap),
		factory: cfg.Factory,
		close: cfg.Close,
		idleTimeout: cfg.IdleTimeout,
	}

	if cfg.Ping != nil {
		c.ping = cfg.Ping
	}

	for i := 0; i < cfg.InitialCap; i++ {
		conn, err := c.factory()
		if err != nil {
			c.Release()
			return nil, fmt.Errorf("factory can't fill channl pool")
		}
		c.conns <-&idleConn{conn: conn, t: time.Now()}
	}
	return c, nil
}

